/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#include "simodo/ast/generator/FormationWrapper.h"

#include <cassert>

namespace simodo::ast
{
    void FormationWrapper::addNode(const std::u16string & host, 
                                OperationCode op, 
                                const inout::Token & op_symbol, 
                                const inout::Token & bound)
    {
        FormationFlow & stream = getStream_mutable(_current_stream_no);

        stream.addNode(host, op, op_symbol, bound);
    }

    void FormationWrapper::addNode_StepInto(const std::u16string & host, 
                                OperationCode op, 
                                const inout::Token & op_symbol, 
                                const inout::Token & bound)
    {
        FormationFlow & stream = getStream_mutable(_current_stream_no);

        stream.addNode_StepInto(host, op, op_symbol, bound);
    }

    bool FormationWrapper::goParent()
    {
        FormationFlow & stream = getStream_mutable(_current_stream_no);

        return stream.goParent();
    }

    void FormationWrapper::addFile(const std::string & file_path)
    {
        auto it = _ast_streams.find(_current_stream_no);

        if (it == _ast_streams.end()) 
            return;

        it->second.addFile(file_path);
    }

    const ast::Tree & FormationWrapper::tree() const  
    {
        if (!_tree.root().branches().empty())
            return _tree;

        auto it = _ast_streams.find(_current_stream_no);

        if (it == _ast_streams.end()) {
            static Tree static_ast;
            return static_ast;
        }

        return it->second.tree(); 
    }

    void FormationWrapper::finalize()
    {
        _tree._root._branches.swap(_main_stream._tree._root._branches);
        _tree._files.swap(_main_stream._tree._files);
        
        auto & wb = _tree._root._branches;

        for(auto & [no,s] : _ast_streams) {
            assert(no != DEFAULT_STREAM_NO);

            auto & sb = s._tree._root.branches();

            wb.insert(wb.end(), sb.begin(), sb.end());
        }
    }

    const FormationFlow &FormationWrapper::getStream(uint16_t no)
    {
        static FormationFlow dummy;

        auto it = _ast_streams.find(no);

        if (it == _ast_streams.end())
            return dummy;

        return it->second;
    }

    void FormationWrapper::removeStream(uint16_t no)
    {
        _ast_streams.erase(no);
    }

    FormationFlow &FormationWrapper::getStream_mutable(uint16_t stream_no)
    {
        if (stream_no == DEFAULT_STREAM_NO)
            return _main_stream;

        /// \todo Нужно оптимизировать из соображений, что чаще всего будет работать один номер потока

        auto it = _ast_streams.find(stream_no);

        if (it != _ast_streams.end())
            return it->second;

        auto [it_new, ok] = _ast_streams.emplace(stream_no,FormationFlow());

        assert(ok);

        return it_new->second;
    }

}